package pl.mchaniewski.ryneczek.screenscrapping.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import pl.mchaniewski.ryneczek.pojo.Quotation;
import pl.mchaniewski.ryneczek.screenscrapping.ContinuousTrading;

@Component("continuousScrapper")
public class MoneyPlScrapper implements ContinuousTrading {
    private static final Logger logger = LoggerFactory
            .getLogger(MoneyPlScrapper.class);
    private static String MONEY_PL_URL = "http://www.money.pl/gielda/gpw/akcje/";
    private static String MAIN_TABLE = "table[class=tabela big]";
    private static String ROWS = "tr[class=tr1], tr[class=tr2]";
    private static String COLUMN = "td[class=al], td[class=ar], td[class=ar last]";
    private static Integer COMPANY_NAME_COLUMN = 0;
    private static Integer OPEN_VALUE_COLUMN = 2;
    private static Integer MIN_VALUE_COLUMN = 3;
    private static Integer MAX_VALUE_COLUMN = 4;
    private static Integer CURRENT_VALUE_COLUMN = 5;
    private static Integer DAILY_CHANGE_VALUE_COLUMN = 6;
    private static Integer TIME_VALUE_COLUMN = 7;
    private static Integer TRADING_VOLUME_VALUE_COLUMN = 8;
    private static Integer MARKET_VALUE_COLUMN = 9;
    private static String NO_VALUE_MARKER = "-";
    private static String TIME_FORMAT = "HH:mm";

    @Override
    public Map<String, Quotation> getAll() {
        logger.info("jSoup screen scrapping began. Source: {}", MONEY_PL_URL);

        try {
            Document doc = Jsoup.connect(MONEY_PL_URL).get();

            Map<String, Quotation> map = new LinkedHashMap<String, Quotation>(0);

            Elements mainTable = doc.select(MAIN_TABLE);
            Elements rows = mainTable.select(ROWS);

            for (Element row : rows) {
                String companyName = row.select(COLUMN)
                        .get(COMPANY_NAME_COLUMN).text();

                if (map.containsKey(companyName)) {
                    logger.warn(
                            "Same company appeared twice in same run. Name: {}",
                            companyName);

                    continue;
                }

                String openS = row.select(COLUMN).get(OPEN_VALUE_COLUMN).text()
                        .trim().replace(",", ".");
                String minS = row.select(COLUMN).get(MIN_VALUE_COLUMN).text()
                        .trim().replace(",", ".");
                String maxS = row.select(COLUMN).get(MAX_VALUE_COLUMN).text()
                        .trim().replace(",", ".");
                String currS = row.select(COLUMN).get(CURRENT_VALUE_COLUMN)
                        .text().trim().replace(",", ".");
                String daily = row.select(COLUMN)
                        .get(DAILY_CHANGE_VALUE_COLUMN).text().trim()
                        .replace(",", ".");
                String timeS = row.select(COLUMN).get(TIME_VALUE_COLUMN).text()
                        .trim();
                String volumeS = row.select(COLUMN)
                        .get(TRADING_VOLUME_VALUE_COLUMN).text().trim();
                String marketS = row.select(COLUMN).get(MARKET_VALUE_COLUMN)
                        .text().trim();

                if (openS.equals(NO_VALUE_MARKER)
                        || minS.equals(NO_VALUE_MARKER)
                        || maxS.equals(NO_VALUE_MARKER)
                        || currS.equals(NO_VALUE_MARKER)
                        || daily.equals(NO_VALUE_MARKER)
                        || timeS.equals(NO_VALUE_MARKER)
                        || volumeS.equals(NO_VALUE_MARKER)
                        || marketS.equals(NO_VALUE_MARKER)) {
                    continue;
                }

                BigDecimal openValue = new BigDecimal(openS);
                BigDecimal minValue = new BigDecimal(minS);
                BigDecimal maxValue = new BigDecimal(maxS);
                BigDecimal currentValue = new BigDecimal(currS);
                Float dailyChange = daily.equals("") ? null : Float
                        .parseFloat(daily);

                DateFormat df = new SimpleDateFormat(TIME_FORMAT);
                Date time = df.parse(timeS);
                Calendar timeNow = Calendar.getInstance();
                Calendar timeTemp = Calendar.getInstance();
                timeTemp.setTime(time);
                timeTemp.set(Calendar.YEAR, timeNow.get(Calendar.YEAR));
                timeTemp.set(Calendar.MONTH, timeNow.get(Calendar.MONTH));
                timeTemp.set(Calendar.DAY_OF_MONTH,
                        timeNow.get(Calendar.DAY_OF_MONTH));

                Integer tradingVolume = Integer.parseInt(volumeS);
                Integer marketValue = Integer.parseInt(marketS);

                Quotation quot = new Quotation();
                quot.setOpenValue(openValue);
                quot.setMinimumValue(minValue);
                quot.setMaximumValue(maxValue);
                quot.setCurrentValue(currentValue);
                quot.setDailyChange(dailyChange);
                quot.setListingDate(timeTemp.getTime());
                quot.setTradingVolume(tradingVolume);
                quot.setMarketValue(marketValue);

                map.put(companyName, quot);
            }

            logger.info("Success! Scrapped {} quotations", map.size());

            return map;
        } catch (IOException ex) {
            logger.warn(
                    "jSoup couldn't grab information from {} Exception details: {}",
                    MONEY_PL_URL, ex.getMessage());
        } catch (NumberFormatException ex) {
            logger.warn(
                    "jSoup couldn't parse one of values from {} Exception details: {}",
                    MONEY_PL_URL, ex.getMessage());
        } catch (ParseException ex) {
            logger.warn(
                    "jSoup couldn't parse date values from {} Exception details: {}",
                    MONEY_PL_URL, ex.getMessage());
        } catch (Exception ex) {
            logger.warn(
                    "jSoup had problems with parsing {} Exception details: {}",
                    MONEY_PL_URL, ex.getMessage());
        }

        return null;
    }
}
